home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 43 / Amiga Format CD43 (1999)(Future Publishing)(GB)(Track 1 of 2)[!][issue 1999-09].iso / -serious- / programming / other / python-1.52 / demo / scripts / newslist.py < prev    next >
Text File  |  1999-06-14  |  11KB  |  367 lines

  1. #! /usr/bin/env python
  2. #######################################################################
  3. # Newslist  $Revision: 1.10 $
  4. #
  5. # Syntax:
  6. #    newslist [ -a ]
  7. #
  8. # This is a program to create a directory full of HTML pages 
  9. # which between them contain links to all the newsgroups available
  10. # on your server.
  11. #
  12. # The -a option causes a complete list of all groups to be read from 
  13. # the server rather than just the ones which have appeared since last
  14. # execution. This recreates the local list from scratch. Use this on
  15. # the first invocation of the program, and from time to time thereafter.
  16. #   When new groups are first created they may appear on your server as 
  17. # empty groups. By default, empty groups are ignored by the -a option.
  18. # However, these new groups will not be created again, and so will not
  19. # appear in the server's list of 'new groups' at a later date. Hence it
  20. # won't appear until you do a '-a' after some articles have appeared.
  21. # I should really keep a list of ignored empty groups and re-check them
  22. # for articles on every run, but I haven't got around to it yet.
  23. #
  24. # This assumes an NNTP news feed.
  25. #
  26. # Feel free to copy, distribute and modify this code for 
  27. # non-commercial use. If you make any useful modifications, let me 
  28. # know!
  29. #
  30. # (c) Quentin Stafford-Fraser 1994
  31. # fraser@europarc.xerox.com                     qs101@cl.cam.ac.uk
  32. #                                                                     #
  33. #######################################################################
  34. import sys,nntplib, string, marshal, time, os, posix, string
  35.  
  36. #######################################################################
  37. # Check these variables before running!                               #
  38.  
  39. # Top directory.
  40. # Filenames which don't start with / are taken as being relative to this.
  41. topdir='/anfs/qsbigdisc/web/html/newspage'
  42.  
  43. # The name of your NNTP host
  44. # eg. 
  45. #    newshost = 'nntp-serv.cl.cam.ac.uk'
  46. # or use following to get the name from the NNTPSERVER environment 
  47. # variable:
  48. #    newshost = posix.environ['NNTPSERVER']
  49. newshost = 'nntp-serv.cl.cam.ac.uk'
  50.  
  51. # The filename for a local cache of the newsgroup list
  52. treefile = 'grouptree'
  53.  
  54. # The filename for descriptions of newsgroups
  55. # I found a suitable one at ftp.uu.net in /uunet-info/newgroups.gz
  56. # You can set this to '' if you don't wish to use one.
  57. descfile = 'newsgroups'
  58.  
  59. # The directory in which HTML pages should be created
  60. # eg.
  61. #   pagedir  = '/usr/local/lib/html/newspage'
  62. #   pagedir  = 'pages' 
  63. pagedir  = topdir
  64.  
  65. # The html prefix which will refer to this directory
  66. # eg. 
  67. #   httppref = '/newspage/', 
  68. # or leave blank for relative links between pages: (Recommended)
  69. #   httppref = ''
  70. httppref = ''
  71.  
  72. # The name of the 'root' news page in this directory. 
  73. # A .html suffix will be added.
  74. rootpage = 'root'
  75.  
  76. # Set skipempty to 0 if you wish to see links to empty groups as well.
  77. # Only affects the -a option.
  78. skipempty = 1
  79.  
  80. # pagelinkicon can contain html to put an icon after links to
  81. # further pages. This helps to make important links stand out.
  82. # Set to '' if not wanted, or '...' is quite a good one.
  83. pagelinkicon='... <img src="http://pelican.cl.cam.ac.uk/icons/page.xbm"> '
  84.  
  85. # ---------------------------------------------------------------------
  86. # Less important personal preferences:
  87.  
  88. # Sublistsize controls the maximum number of items the will appear as
  89. # an indented sub-list before the whole thing is moved onto a different
  90. # page. The smaller this is, the more pages you will have, but the 
  91. # shorter each will be.
  92. sublistsize = 4
  93.  
  94. # That should be all.                                                 #
  95. #######################################################################
  96.  
  97. for dir in os.curdir, os.environ['HOME']:
  98.     rcfile = os.path.join(dir, '.newslistrc.py')
  99.     if os.path.exists(rcfile):
  100.         print rcfile
  101.         execfile(rcfile)
  102.         break
  103.  
  104. from nntplib import NNTP
  105. from stat import *
  106.  
  107. rcsrev = '$Revision: 1.10 $'
  108. rcsrev = string.join(filter(lambda s: '$' not in s, string.split(rcsrev)))
  109. desc = {}
  110.  
  111. # Make (possibly) relative filenames into absolute ones
  112. treefile = os.path.join(topdir,treefile)
  113. descfile = os.path.join(topdir,descfile)
  114. page = os.path.join(topdir,pagedir)
  115.  
  116. # First the bits for creating trees ---------------------------
  117.  
  118. # Addtotree creates/augments a tree from a list of group names
  119. def addtotree(tree, groups):
  120.    print 'Updating tree...'
  121.    for i in groups:
  122.         parts = string.splitfields(i,'.')
  123.         makeleaf(tree, parts)
  124.  
  125. # Makeleaf makes a leaf and the branch leading to it if necessary
  126. def makeleaf(tree,path):
  127.    j = path[0]
  128.    l = len(path)
  129.  
  130.    if not tree.has_key(j):
  131.       tree[j] = {}
  132.    if l == 1:
  133.       tree[j]['.'] = '.'
  134.    if l > 1:
  135.       makeleaf(tree[j],path[1:])
  136.  
  137. # Then the bits for outputting trees as pages ----------------  
  138.  
  139. # Createpage creates an HTML file named <root>.html containing links
  140. # to those groups beginning with <root>.
  141.  
  142. def createpage(root, tree, p):
  143.    filename = os.path.join(pagedir,root+'.html')
  144.    if root == rootpage:
  145.       detail = ''
  146.    else:
  147.       detail = ' under ' + root
  148.    f = open(filename,'w')
  149.    # f.write('Content-Type: text/html\n')
  150.    f.write('<TITLE>Newsgroups available' + detail + '</TITLE>\n')
  151.    f.write('<H1>Newsgroups available' + detail +'</H1>\n')
  152.    f.write('<A HREF="'+httppref+rootpage+'.html">Back to top level</A><P>\n')
  153.    printtree(f,tree,0,p)
  154.    f.write('<I>This page automatically created by \'newslist\' v. '+rcsrev+'.')
  155.    f.write(time.ctime(time.time()) + '</I><P>')
  156.    f.close()
  157.  
  158. # Printtree prints the groups as a bulleted list.  Groups with
  159. # more than <sublistsize> subgroups will be put on a separate page.
  160. # Other sets of subgroups are just indented.
  161.  
  162. def printtree(f, tree, indent, p):
  163.    global desc
  164.    l = len(tree)
  165.  
  166.    if l > sublistsize and indent>0:
  167.       # Create a new page and a link to it
  168.       f.write('<LI><B><A HREF="'+httppref+p[1:]+'.html">')
  169.       f.write(p[1:]+'.*')
  170.       f.write('</A></B>'+pagelinkicon+'\n')
  171.       createpage(p[1:], tree, p)
  172.       return
  173.  
  174.    kl = tree.keys()
  175.  
  176.    if l > 1:
  177.       kl.sort()
  178.       if indent > 0:
  179.          # Create a sub-list
  180.          f.write('<LI>'+p[1:]+'\n<UL>')
  181.       else:
  182.          # Create a main list
  183.          f.write('<UL>')
  184.       indent = indent + 1
  185.    
  186.    for i in kl:
  187.       if i == '.':
  188.          # Output a newsgroup
  189.          f.write('<LI><A HREF="news:' + p[1:] + '">'+ p[1:] + '</A> ')
  190.          if desc.has_key(p[1:]):
  191.             f.write('     <I>'+desc[p[1:]]+'</I>\n')
  192.          else:
  193.             f.write('\n')
  194.       else:
  195.          # Output a hierarchy
  196.          printtree(f,tree[i], indent, p+'.'+i)
  197.  
  198.    if l > 1:
  199.       f.write('\n</UL>')
  200.  
  201. # Reading descriptions file ---------------------------------------
  202.  
  203. # This returns an array mapping group name to its description
  204.  
  205. def readdesc(descfile):
  206.    global desc
  207.  
  208.    desc = {}
  209.  
  210.    if descfile == '':
  211.         return
  212.  
  213.    try:
  214.       d = open(descfile, 'r')
  215.       print 'Reading descriptions...'
  216.    except (IOError):
  217.       print 'Failed to open description file ' + descfile
  218.       return
  219.    l = d.readline()
  220.    while l != '':
  221.       bits = string.split(l)
  222.       try:
  223.          grp = bits[0]
  224.          dsc = string.join(bits[1:])
  225.          if len(dsc)>1:
  226.             desc[grp] = dsc
  227.       except (IndexError):
  228.          pass
  229.       l = d.readline()
  230.  
  231. # Check that ouput directory exists, ------------------------------
  232. # and offer to create it if not
  233.  
  234. def checkopdir(pagedir):
  235.    if not os.path.isdir(pagedir):
  236.       print 'Directory '+pagedir+' does not exist.'
  237.       print 'Shall I create it for you? (y/n)'
  238.       if sys.stdin.readline()[0] == 'y':
  239.          try:
  240.             os.mkdir(pagedir,0777)
  241.          except:
  242.             print 'Sorry - failed!'
  243.             sys.exit(1)
  244.       else:
  245.          print 'OK. Exiting.'
  246.          sys.exit(1)
  247.  
  248. # Read and write current local tree ----------------------------------
  249.  
  250. def readlocallist(treefile):
  251.       print 'Reading current local group list...'
  252.       tree = {}
  253.       try:
  254.          treetime = time.localtime(os.stat(treefile)[ST_MTIME])
  255.       except:
  256.          print '\n*** Failed to open local group cache '+treefile
  257.          print 'If this is the first time you have run newslist, then'
  258.          print 'use the -a option to create it.'
  259.          sys.exit(1)
  260.       treedate = '%02d%02d%02d' % (treetime[0] % 100 ,treetime[1], treetime[2])
  261.       try:
  262.          dump = open(treefile,'r')
  263.          tree = marshal.load(dump)
  264.          dump.close()
  265.       except (IOError):
  266.          print 'Cannot open local group list ' + treefile
  267.       return (tree, treedate)
  268.  
  269. def writelocallist(treefile, tree):
  270.    try:
  271.       dump = open(treefile,'w')
  272.       groups = marshal.dump(tree,dump)
  273.       dump.close()
  274.       print 'Saved list to '+treefile+'\n'
  275.    except:
  276.       print 'Sorry - failed to write to local group cache '+treefile
  277.       print 'Does it (or its directory) have the correct permissions?'
  278.       sys.exit(1)
  279.  
  280. # Return list of all groups on server -----------------------------
  281.  
  282. def getallgroups(server):
  283.    print 'Getting list of all groups...'
  284.    treedate='010101'
  285.    info = server.list()[1]
  286.    groups = []
  287.    print 'Processing...'
  288.    if skipempty:
  289.       print '\nIgnoring following empty groups:'
  290.    for i in info:
  291.       grpname = string.split(i[0])[0]
  292.       if skipempty and string.atoi(i[1]) < string.atoi(i[2]):
  293.          print grpname+' ',
  294.       else:
  295.          groups.append(grpname)
  296.    print '\n'
  297.    if skipempty:
  298.       print '(End of empty groups)'
  299.    return groups
  300.  
  301. # Return list of new groups on server -----------------------------
  302.  
  303. def getnewgroups(server, treedate):
  304.    print 'Getting list of new groups since start of '+treedate+'...',
  305.    info = server.newgroups(treedate,'000001')[1]
  306.    print 'got '+`len(info)`+'.'
  307.    print 'Processing...',
  308.    groups = []
  309.    for i in info:
  310.       grpname = string.split(i)[0]
  311.       groups.append(grpname)
  312.    print 'Done'
  313.    return groups
  314.  
  315. # Now the main program --------------------------------------------
  316.  
  317. def main():
  318.    global desc
  319.  
  320.    tree={}
  321.  
  322.    # Check that the output directory exists
  323.    checkopdir(pagedir);
  324.  
  325.    try:
  326.       print 'Connecting to '+newshost+'...'
  327.       if sys.version[0] == '0':
  328.          s = NNTP.init(newshost)
  329.       else:
  330.          s = NNTP(newshost)
  331.       connected = 1
  332.    except (nntplib.error_temp, nntplib.error_perm), x:
  333.       print 'Error connecting to host:', x
  334.       print 'I\'ll try to use just the local list.'
  335.       connected = 0
  336.  
  337.    # If -a is specified, read the full list of groups from server   
  338.    if connected and len(sys.argv) > 1 and sys.argv[1] == '-a':
  339.  
  340.      groups = getallgroups(s)
  341.  
  342.    # Otherwise just read the local file and then add
  343.    # groups created since local file last modified.
  344.    else:
  345.  
  346.       (tree, treedate) = readlocallist(treefile)
  347.       if connected:
  348.          groups = getnewgroups(s, treedate)
  349.       
  350.    if connected:
  351.       addtotree(tree, groups)
  352.       writelocallist(treefile,tree)
  353.  
  354.    # Read group descriptions
  355.    readdesc(descfile)
  356.  
  357.    print 'Creating pages...'
  358.    createpage(rootpage, tree, '')
  359.    print 'Done'
  360.  
  361.  
  362. main()
  363.  
  364. # That's all folks
  365. ######################################################################
  366.